
from fastapi import FastAPI, HTTPException, Depends, HTTPException, Query, Request
import time
from dotenv import load_dotenv, find_dotenv
from powder_compounding import powder_compounding_router
import os
import hashlib
from pydantic import BaseModel
import uuid
from densest_accumulation import densest_accumulation_router
from datetime import datetime
import sqlalchemy as sa
import json
from databases import Database
from logger import logger
from sqlalchemy import create_engine,Column,String,Integer,Text,DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import chardet
app = FastAPI(docs_url="/")
from auth import Auth
import requests
load_dotenv(find_dotenv())
APP_ID = os.getenv("APP_ID")
APP_SECRET = os.getenv("APP_SECRET")
FEISHU_HOST = os.getenv("FEISHU_HOST")
NONCE_STR = os.getenv("NONCE_STR")
MAPPING_FILE = os.getenv("MAPPING_FILE")
app.include_router(powder_compounding_router, prefix="/pc", tags=["粉末配比计算"])
app.include_router(densest_accumulation_router, prefix="/da", tags=["最密堆积计算"])

class UserInfoRequest(BaseModel):
    displayName: str

metadata = sa.MetaData()
audit_logs = sa.Table(
    "audit_logs",
    metadata,
    sa.Column("id", sa.Integer, primary_key=True),
    sa.Column("user_id", sa.String, nullable=False),
    sa.Column("action", sa.String, nullable=False),
    sa.Column("request_time", sa.DateTime, nullable=False),
    sa.Column("request_info", sa.JSON, nullable=True)
)

from fastapi.responses import RedirectResponse

# 数据库配置
# DATABASE_URL = "sqlite:///./db/audit.db"
# database = Database(DATABASE_URL)
#
# # 创建数据库表
# engine = sa.create_engine(DATABASE_URL)
# metadata.create_all(engine)

HOSTNAME = '127.0.0.1'
PORT = "3306"
USERNAME = "root"
PASSWORD = "Bmdatabase123!"
DATABASE = "powder"
DB_URI = "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8".format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)
engine = create_engine(DB_URI)

Base = declarative_base()

session = sessionmaker(engine)()
# Base.metadata.create_all(bind=engine)
class Weblog(Base):
    __tablename__ = "web_log"
    id = Column(Integer, primary_key=True)
    method = Column(String(255))
    oper_name = Column(String(255))
    desc = Column(Text)
    oper_time = Column(DateTime, default=datetime.now)


# 启动和关闭数据库连接
# @app.on_event("startup")
# async def startup():
#     await database.connect()
#
# @app.on_event("shutdown")
# async def shutdown():
#     await database.disconnect()

# 日志中间件
@app.middleware("http")
async def audit_log_middleware(request: Request, call_next):
    content_type = request.headers.get('Content-Type')
    if content_type and 'multipart/form-data; boundary=' in content_type:
        body = dict(request.query_params.items())
        # for key, value in form_data.multi_items():
        #     if hasattr(value, 'filename') and value.filename:  # 检查是否是文件上传字段
        #         file_names.append(value.filename)
        # if file_names:
        #     body["file_names"] = file_names
    else :
        body = await request.body()
        if body.decode() == "":
            body = dict(request.query_params.items())
        else:
            body = json.loads(body.decode())


    response = await call_next(request)
    try:
        route = request.scope.get("route")
        if route is not None:
            endpoint = route.endpoint
            action = getattr(endpoint, "__audit_action__", None)
            user_name = body.get("user_name", None)
            user_id = body.get("user_id", None)
            if action and user_name:
                if user_id:
                    body.pop("user_id")
                body.pop("user_name")
                log = Weblog(oper_name=user_name,method=action,oper_time=datetime.now(),desc=str(body))
                session.add(log)  # 添加物品
                session.commit()  # 提交事务
                session.refresh(log)  # 刷新数据

    except Exception as e:
        logger.error(f"Audit log error: {str(e)}  Dont need save")

    return response


@app.get("/get_config_parameters")
async def get_config_parameters(url: str):
    try:
        ticket = Auth(FEISHU_HOST, APP_ID, APP_SECRET).get_ticket()
        timestamp = int(time.time()) * 1000
        verify_str = f"jsapi_ticket={ticket}&noncestr={NONCE_STR}&timestamp={timestamp}&url={url}"
        signature = hashlib.sha1(verify_str.encode("utf-8")).hexdigest()
        return {
            "appid": APP_ID,
            "signature": signature,
            "noncestr": NONCE_STR,
            "timestamp": timestamp
        }
    except Exception as e:
        raise HTTPException(500, str(e))
    

@app.post("/save_user_info")
async def save_user_info(request_data: UserInfoRequest):
    display_name = request_data.displayName
    user_map = load_mapping()

    if not display_name:
        raise HTTPException(400, "Missing displayName")

    if display_name in user_map:
        return {"code": user_map[display_name]}
    
    unique_code = uuid.uuid4().hex
    user_map[display_name] = unique_code
    save_mapping(display_name, unique_code)
    os.makedirs(os.path.join('storage', unique_code), exist_ok=True)
    return {"code": unique_code}

@app.post("/get_user_folder")
async def get_user_folder(request_data: UserInfoRequest):
    user_map = load_mapping()
    display_name = request_data.displayName
    
    if not display_name:
        raise HTTPException(400, "Missing displayName")

    if folder_name := user_map.get(display_name):
        return {"folderName": folder_name}
    raise HTTPException(404, "User not found")

# --------------------------
# 工具函数
# --------------------------
def load_mapping():
    mapping = {}
    if os.path.exists(MAPPING_FILE):
        with open(MAPPING_FILE, "r") as f:
            for line in f:
                k, v = line.strip().split(',')
                mapping[k] = v
    return mapping

def save_mapping(display_name: str, folder_name: str):
    with open(MAPPING_FILE, "a") as f:
        f.write(f"{display_name},{folder_name}\n")




# # 日志查询接口
# @app.get("/logs")
# async def get_logs(page: int = Query(1, ge=1)):
#     offset = (page - 1) * 20
#     query = audit_logs.select().order_by(sa.desc(audit_logs.c.request_time)).offset(offset).limit(20)
#     return {"logs": await database.fetch_all(query)}
#
# @app.get("/logs/{user_id}")
# async def get_user_logs(user_id: int, page: int = Query(1, ge=1)):
#     offset = (page - 1) * 20
#     query = audit_logs.select().where(
#         audit_logs.c.user_id == user_id
#     ).order_by(sa.desc(audit_logs.c.request_time)).offset(offset).limit(20)
#     return {"logs": await database.fetch_all(query)}


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app=app, host="0.0.0.0", port=8101)